home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BMUG Revelations
/
BMUG Revelations.toast
/
Utilities
/
System 7
/
ChooserHack
/
ChooserHack.c
next >
Wrap
Text File
|
1993-06-16
|
20KB
|
708 lines
/*
File: ChooserHack.c
Contains: Code to maintain a directory hierarchy that maps to zones, file servers, and volumes
Written by: Nick Kledzik
Date: June 93
For: MacHack 93
*/
#define SystemSevenOrLater 1
#include <StdDef.h>
#include <Memory.h>
#include <AppleTalk.h>
#include <Folders.h>
#include <Errors.h>
#include <Files.h>
#include <Resources.h>
#include <Aliases.h>
// inlines that should have been in AppleTalk.h
#pragma parameter __D0 GetZoneListSync(__A0)
pascal OSErr GetZoneListSync(XPPParmBlkPtr paramBlock)
= {0x317C, 0x0006, 0x001C, 0x317C, 0xFFD7, 0x0018, 0x317C, 0x00F6, 0x001A, 0xA004};
#pragma parameter __D0 PLookupNameSync(__A0)
pascal OSErr PLookupNameSync(MPPPBPtr paramBlock)
= {0x317C, 0x00FB, 0x001A, 0x317C, 0xFFF6, 0x0018, 0xA004};
#pragma parameter __D0 ASPGetStatusSync(__A0)
pascal OSErr ASPGetStatusSync(XPPParmBlkPtr paramBlock)
= {0x317C, 0x00FB, 0x001A, 0xA004};
#pragma parameter __D0 AFPCommandSync(__A0)
pascal OSErr AFPCommandSync(XPPParmBlkPtr paramBlock)
= {0x317C, 0x00FA, 0x001A, 0xA004};
// inline that should have been in Files.h
#pragma parameter __D0 PBMountAFPVolSync(__A0)
pascal OSErr PBMountAFPVolSync(ParmBlkPtr paramBlock)
= {0x7041,0xA260};
struct Globals
{
short theNetworkVRefNum;
long theNetworkFolderID;
};
typedef struct Globals Globals;
extern Globals* GetGlobals();
extern void InstallPatches();
void SetCustomFolderIcon(short vRefNum, long dirID, short iconID)
{
CInfoPBRec cpb;
OSErr err;
Handle icl8;
Handle icl4;
Handle ICNP;
Handle ics8;
Handle ics4;
Handle icsP;
short ref;
Str32 netFolderName;
Str32 iconFilename;
// get folder icon resources
icl8 = GetResource('icl8', iconID);
icl4 = GetResource('icl4', iconID);
ICNP = GetResource('ICN#', iconID);
ics8 = GetResource('ics8', iconID);
ics4 = GetResource('ics4', iconID);
icsP = GetResource('ics#', iconID);
DetachResource(icl8);
DetachResource(icl4);
DetachResource(ICNP);
DetachResource(ics8);
DetachResource(ics4);
DetachResource(icsP);
// make icon file in folder and add resources
BlockMove("\pIcon\015", iconFilename, 6);
HCreateResFile(vRefNum, dirID, iconFilename);
ref = HOpenResFile(vRefNum, dirID, iconFilename, fsCurPerm);
AddResource(icl8, 'icl8', -16455, "\p");
AddResource(icl4, 'icl4', -16455, "\p");
AddResource(ICNP, 'ICN#', -16455, "\p");
AddResource(ics8, 'ics8', -16455, "\p");
AddResource(ics4, 'ics4', -16455, "\p");
AddResource(icsP, 'ics#', -16455, "\p");
CloseResFile(ref);
// make file invisible
cpb.hFileInfo.ioVRefNum = vRefNum;
cpb.hFileInfo.ioDirID = dirID;
cpb.hFileInfo.ioNamePtr = iconFilename;
cpb.hFileInfo.ioFDirIndex = 0;
cpb.hFileInfo.ioFlFndrInfo.fdType = 'nick'; // flag to avoid recursion
err = PBGetCatInfoSync(&cpb);
if (err == noErr)
{
cpb.hFileInfo.ioVRefNum = vRefNum;
cpb.hFileInfo.ioDirID = dirID;
cpb.hFileInfo.ioNamePtr = iconFilename;
cpb.hFileInfo.ioFDirIndex = 0;
cpb.hFileInfo.ioFlFndrInfo.fdFlags |= 0x4000; // set invisible flag
err = PBSetCatInfoSync(&cpb);
}
// mark that folder uses a custom icon
cpb.dirInfo.ioVRefNum = vRefNum;
cpb.dirInfo.ioDrDirID = dirID;
cpb.dirInfo.ioNamePtr = netFolderName;
cpb.dirInfo.ioFDirIndex = -1;
err = PBGetCatInfoSync(&cpb);
if (err == noErr)
{
cpb.dirInfo.ioDrDirID = cpb.dirInfo.ioDrParID;
cpb.dirInfo.ioNamePtr = netFolderName;
cpb.dirInfo.ioFDirIndex = 0;
cpb.hFileInfo.ioFlFndrInfo.fdFlags |= 0x0400; // set custom icon flag
err = PBSetCatInfoSync(&cpb);
}
}
////////////////////////////////////////////////////////////
//
// Create "The Network" folder if it does not exist.
// Initializes globals->theNetworkVRefNum and globals->theNetworkFolderID
//
OSErr CreateTheNetworkFolder(void)
{
FSSpec theNetworkFolder;
OSErr err;
CInfoPBRec cpb;
Globals* globals = GetGlobals();
err = FindFolder(kOnSystemDisk, kDesktopFolderType, kDontCreateFolder, &theNetworkFolder.vRefNum, &theNetworkFolder.parID);
if (err) return err;
globals->theNetworkVRefNum = theNetworkFolder.vRefNum;
BlockMove("\pThe Network", &theNetworkFolder.name, 12);
cpb.dirInfo.ioVRefNum = theNetworkFolder.vRefNum;
cpb.dirInfo.ioDrDirID = theNetworkFolder.parID;
cpb.dirInfo.ioNamePtr = (StringPtr)&theNetworkFolder.name;
cpb.dirInfo.ioFDirIndex = 0;
cpb.hFileInfo.ioFlFndrInfo.fdType = 'nick'; // flag to avoid recursion
err = PBGetCatInfoSync(&cpb);
if (err == noErr)
globals->theNetworkFolderID = cpb.dirInfo.ioDrDirID;
else if (err == fnfErr)
{
err = FSpDirCreate(&theNetworkFolder, -1, &globals->theNetworkFolderID);
if (err == noErr)
{
SetCustomFolderIcon(globals->theNetworkVRefNum,globals->theNetworkFolderID, 128);
}
}
return err;
}
////////////////////////////////////////////////////////////
//
// Make sure there is a folder in <vRefNum,parID> with name folderName
//
OSErr SyncFolder(short vRefNum, long parID, const char* folderName, long* folderDirID)
{
CInfoPBRec cpb;
OSErr err;
// see if folder exists
cpb.dirInfo.ioVRefNum = vRefNum;
cpb.dirInfo.ioDrDirID = parID;
cpb.dirInfo.ioNamePtr = (StringPtr)folderName;
cpb.dirInfo.ioFDirIndex = 0;
cpb.hFileInfo.ioFlFndrInfo.fdType = 'nick'; // flag to avoid recursion
err = PBGetCatInfoSync(&cpb);
*folderDirID = cpb.dirInfo.ioDrDirID;
if (err == fnfErr)
{
HParamBlockRec hpb;
// create a folder aZoneName
hpb.fileParam.ioVRefNum = vRefNum;
hpb.fileParam.ioNamePtr = (StringPtr)folderName;
hpb.fileParam.ioDirID = parID;
err = PBDirCreateSync(&hpb);
if ( err == noErr )
{
*folderDirID = hpb.fileParam.ioDirID; // get return result
// set special bit in folder info
cpb.dirInfo.ioVRefNum = vRefNum;
cpb.dirInfo.ioDrDirID = parID;
cpb.dirInfo.ioNamePtr = (StringPtr)folderName;
cpb.dirInfo.ioFDirIndex = 0;
cpb.hFileInfo.ioFlFndrInfo.fdType = 'nick'; // flag to avoid recursion
err = PBGetCatInfoSync(&cpb);
if ( err == noErr )
{
cpb.dirInfo.ioVRefNum = vRefNum;
cpb.dirInfo.ioDrDirID = parID;
cpb.dirInfo.ioNamePtr = (StringPtr)folderName;
cpb.dirInfo.ioFDirIndex = 0;
cpb.dirInfo.ioDrFndrInfo.frXFlags |= 1; // this bit lets us know it is our folder
cpb.dirInfo.ioDrUsrWds.frView = 0x0200; // set view by name as default
err = PBSetCatInfoSync(&cpb);
};
};
};
return err;
}
////////////////////////////////////////////////////////////
//
// Make sure there is a folder for every zone name
//
void CreateZoneFolders(void)
{
#define kGetZoneListBufferSize 578
Globals* globals = GetGlobals();
char theZoneList[kGetZoneListBufferSize];
OSErr err;
XCallParam pb;
int theZoneListCount = 0;
// get zone list from a bridge
pb.xppTimeout = 2;
pb.xppRetry = 4;
pb.zipBuffPtr = (Ptr)&theZoneList;
pb.zipLastFlag = 0;
pb.zipInfoField[0] = 0;
pb.zipInfoField[1] = 0;
while ( pb.zipLastFlag == 0 )
{
// get each chunk of zone list
err = GetZoneListSync((XPPParmBlkPtr)&pb);
if ( err != noErr ) break;
// offset zipBuffPtr to end of this list
{
long tempDirID;
char* s = pb.zipBuffPtr;
// make sure there is a folder for each zone
while ( pb.zipNumZones-- > 0 )
{
SyncFolder(globals->theNetworkVRefNum, globals->theNetworkFolderID, s, &tempDirID);
s += *s;
s++;
theZoneListCount++;
}
}
}
}
////////////////////////////////////////////////////////////
//
// For every afp server in a zone, make sure there is a folder.
//
void SyncServersInAZone(const char* zoneName)
{
EntityName searchCriteria;
char buffer[1000];
OSErr err;
NBPparms mpb;
Globals* globals = GetGlobals();
// pack entity names
NBPSetEntity((Ptr)&searchCriteria, (Ptr)"\p=", (Ptr)"\pAFPServer", (Ptr)zoneName);
// Do a NBP Lookup
mpb.interval = 8;
mpb.count = 4;
mpb.NBPPtrs.entityPtr = (Ptr)&searchCriteria;
mpb.parm.Lookup.retBuffPtr = buffer;
mpb.parm.Lookup.retBuffSize = 1000;
mpb.parm.Lookup.maxToGet = 100;
err = PLookupNameSync((MPPPBPtr)&mpb);
if (err == noErr)
{
short serverCount = mpb.parm.Lookup.numGotten;
long zoneFolderID;
int i;
// make sure there is a zone folder for this zone
SyncFolder(globals->theNetworkVRefNum, globals->theNetworkFolderID, zoneName, &zoneFolderID);
// for each server found by NBP
for (i = 1; i <= serverCount; i++)
{
AddrBlock address;
EntityName aServer;
long temp;
// make sure there is a server folder for this server
err = NBPExtract(buffer, serverCount, i, &aServer, &address);
if (err == noErr)
SyncFolder(globals->theNetworkVRefNum, zoneFolderID, (const char*)aServer.objStr, &temp);
}
}
}
////////////////////////////////////////////////////////////
//
// Given a zone and server name, find its network address
//
OSErr GetFileServerAddress (const char* zoneName, const char* serverName, AddrBlock* serverAddr)
{
EntityName searchCriteria;
char buffer[120];
OSErr err;
NBPparms mpb;
// pack entity names
NBPSetEntity((Ptr)&searchCriteria, (Ptr)serverName, (Ptr)"\pAFPServer", (Ptr)zoneName);
// Do a NBP Lookup
mpb.interval = 8; // allow 8 ticks before looking again
mpb.count = 2; // allow up to 2 retries
mpb.NBPPtrs.entityPtr = (Ptr)&searchCriteria;
mpb.parm.Lookup.retBuffPtr = buffer;
mpb.parm.Lookup.retBuffSize = 120;
mpb.parm.Lookup.maxToGet = 1; // just looking for 1 thing
err = PLookupNameSync((MPPPBPtr)&mpb);
if ( (err == noErr) && (mpb.parm.Lookup.numGotten == 1) )
{
EntityName aServer;
// make sure there is a server folder for this server
err = NBPExtract(buffer, 1, 1, &aServer, serverAddr);
}
return err;
}
typedef struct {
short machineTypeOffset;
short AFPversOffset;
short UAMStringsOffset;
short iconMaskOffset;
short flags;
Str31 serverName;
Str15 machineType;
char variableData[128+256];
} ASPGetStatusReplyBuf;
////////////////////////////////////////////////////////////
//
// Given a server address, figures out if it support guest login
//
Boolean FileServerAllowsGuests (AddrBlock serverAddr)
{
XPPPrmBlk pb; // param block for ASPGetStatus call
ASPGetStatusReplyBuf buffer; // reply buffer for ASPGetStatus call
pb.ioRefNum = xppRefNum;
pb.aspTimeout = 1; // allow 8 ticks before getting server info again
pb.aspRetry = 2; // allow 2 max retries
*(AddrBlock *)(&pb.cbSize) = serverAddr; // need to stuff AddrBlock at this offset in pb
pb.rbSize = sizeof(ASPGetStatusReplyBuf);
pb.rbPtr = (Ptr)&buffer;
if (ASPGetStatusSync((XPPParmBlkPtr)&pb) == noErr)
{
Ptr uamStringsPtr; // pointer into UAM strings
unsigned char countOfUAMStrings; // count of UAM strings
int i;
uamStringsPtr = ((Ptr)&buffer) + buffer.UAMStringsOffset;
countOfUAMStrings = *uamStringsPtr++; // first byte is count of number of UAM strings
// look for "No User Authent" in list
for (i=1; i <= countOfUAMStrings; ++i)
{
if (EqualString("\pNo User Authent", (StringPtr)uamStringsPtr, false, true))
return true;
else
uamStringsPtr += (Length(uamStringsPtr) +1); // point to the next UAM string
}
// guest login not allowed (could not find "No User Authent" in list)
return false;
}
}
////////////////////////////////////////////////////////////
//
// Given a server name and zone name, find coresponding folder dirID
//
OSErr GetServerFolderID(const char* zoneName, const char* serverName, long* serverDirID)
{
long zoneDirID;
OSErr err;
Globals* globals = GetGlobals();
err = SyncFolder(globals->theNetworkVRefNum, globals->theNetworkFolderID, zoneName, &zoneDirID);
if ( err == noErr )
err = SyncFolder(globals->theNetworkVRefNum, zoneDirID, serverName, serverDirID);
return err;
}
////////////////////////////////////////////////////////////
//
// Given a server address, figures out if it support guest login
//
OSErr CreateVolumeAlias(short serverVRefNum, long serverDirID, const char* volumeName)
{
CInfoPBRec cpb;
OSErr err;
// see if alias exists
cpb.hFileInfo.ioVRefNum = serverVRefNum;
cpb.hFileInfo.ioDirID = serverDirID;
cpb.hFileInfo.ioNamePtr = (StringPtr)volumeName;
cpb.hFileInfo.ioFDirIndex = 0;
cpb.hFileInfo.ioFlFndrInfo.fdType = 'nick'; // flag to avoid recursion
err = PBGetCatInfoSync(&cpb);
if (err == fnfErr)
{
HParamBlockRec hpb;
// create an alias file volumeName
hpb.fileParam.ioVRefNum = serverVRefNum;
hpb.fileParam.ioNamePtr = (StringPtr)volumeName;
hpb.fileParam.ioFlVersNum = 0;
hpb.fileParam.ioDirID = serverDirID;
err = PBHCreateSync(&hpb);
if (err != noErr)
return err;
// get info about it
cpb.hFileInfo.ioVRefNum = serverVRefNum;
cpb.hFileInfo.ioDirID = serverDirID;
cpb.hFileInfo.ioNamePtr = (StringPtr)volumeName;
cpb.hFileInfo.ioFDirIndex = 0;
cpb.hFileInfo.ioFlFndrInfo.fdType = 'nick'; // flag to avoid recursion
err = PBGetCatInfoSync(&cpb);
// set type and creator
cpb.hFileInfo.ioFlFndrInfo.fdType = 'fdrp'; // should be 'srvr' but Finder wants those to have custom icons
cpb.hFileInfo.ioFlFndrInfo.fdCreator = 'MACS';
cpb.hFileInfo.ioFlFndrInfo.fdFlags |= 0x8000; // flip on alias bit
// set new info
cpb.hFileInfo.ioVRefNum = serverVRefNum;
cpb.hFileInfo.ioDirID = serverDirID;
cpb.hFileInfo.ioNamePtr = (StringPtr)volumeName;
cpb.hFileInfo.ioFDirIndex = 0;
err = PBSetCatInfoSync(&cpb);
}
return err;
}
////////////////////////////////////////////////////////////
//
// Given a server, make sure there is a volume alias for each volume
//
OSErr SyncVolumesInAServer(const char* zoneName, const char* serverName)
{
AddrBlock serverAddr;
OSErr err;
Globals* globals = GetGlobals();
if ( ((err=GetFileServerAddress (zoneName, serverName, &serverAddr)) == noErr) && FileServerAllowsGuests(serverAddr) )
{
// log on to AFP server to get volume info
char scb[scbMemSize]; // session control block
char command[32];
AFPLoginPrm loginPB;
char replyBuffer[100];
command[0] = afpLogin;
BlockMove("\pAFPVersion 2.1", (void*)&command[1], 15);
BlockMove("\pNo User Authent", (void*)&command[16], 16);
loginPB.ioRefNum = xppRefNum;
loginPB.aspTimeout = 1; // allow 8 ticks before getting server info again
loginPB.aspRetry = 2; // allow 2 max retries
loginPB.afpAddrBlock= serverAddr;
loginPB.cbSize = 32;
loginPB.cbPtr = (Ptr)&command;
loginPB.rbSize = 100;
loginPB.rbPtr = replyBuffer;
loginPB.afpSCBPtr = (Ptr)&scb; // control block for use during session
loginPB.afpAttnRoutine = NULL;
AFPCommandSync((XPPParmBlkPtr)&loginPB);
err = (loginPB.ioResult ? loginPB.ioResult : loginPB.cmdResult);
if ( err == noErr )
{
// use AFPGetSrvrParms to get list of volume names
char commandBuffer[2];
char replyBuffer[1000];
XPPPrmBlk infoPB;
commandBuffer[0] = afpGetSParms;
infoPB.ioRefNum = xppRefNum;
infoPB.sessRefnum = loginPB.sessRefnum;
infoPB.cbSize = 1;
infoPB.cbPtr = commandBuffer;
infoPB.rbSize = 1000;
infoPB.rbPtr = replyBuffer;
AFPCommandSync((XPPParmBlkPtr)&infoPB);
err = (infoPB.ioResult ? infoPB.ioResult : infoPB.cmdResult);
if ( err == noErr )
{
char* s = &replyBuffer[4]; // skip over server time header
int numVols = *s++; // get number of volumes
int i;
long serverDirID;
err = GetServerFolderID(zoneName, serverName, &serverDirID);
if ( err == noErr )
{
for ( i = 0; i < numVols; ++i)
{
s++; // skip volume attributes byte
CreateVolumeAlias(globals->theNetworkVRefNum, serverDirID, s);
s += (Length(s) + 1);
}
}
}
// logout from server
command[0] = afpLogout;
loginPB.ioRefNum = xppRefNum;
loginPB.cbSize = 1;
loginPB.cbPtr = (Ptr)&command;
AFPCommandSync((XPPParmBlkPtr)&loginPB);
}
}
return err;
}
////////////////////////////////////////////////////////////
//
// Given a folder vRefNum and dirID, return its name and parent folder dirID
//
OSErr GetFolderName(short vRefNum, long folderID, char* folderName, long* parID)
{
CInfoPBRec cpb;
OSErr err;
cpb.dirInfo.ioVRefNum = vRefNum;
cpb.dirInfo.ioDrDirID = folderID;
cpb.dirInfo.ioNamePtr = (StringPtr)folderName;
cpb.dirInfo.ioFDirIndex = -1;
cpb.hFileInfo.ioFlFndrInfo.fdType = 'nick'; // flag to avoid recursion
err = PBGetCatInfoSync(&cpb);
*parID = cpb.dirInfo.ioDrParID;
return err;
}
////////////////////////////////////////////////////////////
//
// Make sure the contents of a special folder is in sync with what is on the network.
//
pascal void SyncSpecialFolder(short vRefNum, long parentFolderID, const unsigned char* folderName)
{
Globals* globals = GetGlobals();
if ( vRefNum == globals->theNetworkVRefNum )
{
if ( parentFolderID == globals->theNetworkFolderID )
{
// this is a zone folder that needs to be synced
SyncServersInAZone(folderName);
}
else
{
// must be a server folder
char zoneName[32];
long temp;
// get zone name it is in and sync it
if ( GetFolderName(vRefNum, parentFolderID, &zoneName[0], &temp) == noErr )
SyncVolumesInAServer(zoneName, folderName);
}
}
}
////////////////////////////////////////////////////////////
//
// When the user tries to use an empty alias, this is called
// to mount the volume and fill in the alias file.
//
pascal short OpenVolumeAliasFile(short vRefNum, long serverFolderID, const unsigned char* volumeName)
{
Globals* globals = GetGlobals();
if ( vRefNum == globals->theNetworkVRefNum )
{
AFPVolMountInfo mountInfo;
ParamBlockRec pb;
long zoneFolderID;
long netFolderID;
if (( GetFolderName(vRefNum, serverFolderID, &mountInfo.AFPData[32], &zoneFolderID) == noErr ) // get servername
&& ( GetFolderName(vRefNum, zoneFolderID, &mountInfo.AFPData[0], &netFolderID) == noErr ) // get zonename
&& ( netFolderID = globals->theNetworkFolderID ) )
{
BlockMove(volumeName, &mountInfo.AFPData[64], 32);
mountInfo.length = sizeof(AFPVolMountInfo);
mountInfo.media = AppleShareMediaType;
mountInfo.flags = 0;
mountInfo.nbpInterval = 0;
mountInfo.nbpCount = 0;
mountInfo.uamType = kNoUserAuthentication;
mountInfo.zoneNameOffset = offsetof(AFPVolMountInfo, AFPData);
mountInfo.serverNameOffset = offsetof(AFPVolMountInfo, AFPData[32]);
mountInfo.volNameOffset = offsetof(AFPVolMountInfo, AFPData[64]);
mountInfo.userNameOffset = offsetof(AFPVolMountInfo, AFPData[96]);
mountInfo.userPasswordOffset = offsetof(AFPVolMountInfo, AFPData[96]);
mountInfo.volPasswordOffset = offsetof(AFPVolMountInfo, AFPData[96]);
mountInfo.AFPData[96] = 0;
pb.ioParam.ioBuffer = (Ptr)&mountInfo;
if ( PBMountAFPVolSync(&pb) == noErr )
{
FSSpec newVolume;
// make FSSpec for volume
newVolume.vRefNum = pb.ioParam.ioVRefNum;
newVolume.parID = 1;
pb.volumeParam.ioVolIndex = -1;
pb.volumeParam.ioNamePtr = newVolume.name;
if ( PBGetVInfoSync(&pb) == noErr )
{
AliasHandle h;
short ref;
// make alias to the volume
if ( NewAliasMinimal(&newVolume, &h) == noErr )
{
HCreateResFile(vRefNum, serverFolderID, volumeName);
ref = HOpenResFile(vRefNum, serverFolderID, volumeName, fsCurPerm);
if ( ref != -1 )
AddResource( (Handle)h, 'alis', 0, volumeName);
else
DisposeHandle((Handle)h);
return ref;
}
}
}
}
return -1;
}
}
void DoInstall()
{
Debugger();
CreateTheNetworkFolder();
CreateZoneFolders();
InstallPatches();
}